package com.cbarmstrong.Finance;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.Date;
import java.util.Vector;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.TimeSeriesDataItem;
import org.jfree.data.xy.OHLCDataItem;
import org.jfree.data.xy.XYDataset;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
//import org.neuroph.core.NeuralNetwork;
//import org.neuroph.core.learning.SupervisedLearning;
//import org.neuroph.core.learning.TrainingSet;
//import org.neuroph.nnet.MultiLayerPerceptron;
//import org.neuroph.util.TransferFunctionType;


public class Ticker implements Cloneable {
	
	private Vector<OHLCDataItem> prices=new Vector<OHLCDataItem>();
	private Vector<Double> opens=new Vector<Double>(), closes=new Vector<Double>(), highs=new Vector<Double>(), lows=new Vector<Double>();
	private Vector<Date> dates=new Vector<Date>();
	private double spread;
	private String ticker;
	int history;
	//private MultiLayerPerceptron mlp;
	//@SuppressWarnings("rawtypes")
	//private TrainingSet trainingSet;
	
	public Ticker(String ticker, int days) throws SQLException{
		this.ticker=ticker;
		Data.storeHistoric(ticker, days);
		prices=Data.getPrices(ticker);
		spread=Data.getSpread(ticker);
		for(int i=0;i<prices.size();i++){
			opens.add((Double) prices.get(i).getOpen());
			highs.add((Double) prices.get(i).getHigh());
			lows.add((Double) prices.get(i).getLow());
			closes.add((Double) prices.get(i).getClose());
			dates.add((Date) prices.get(i).getDate());
		}
		if(dates.size()==0){ System.out.println("Ticker returned with zero points. Exiting."); System.exit(8); }
		Data.getLogger().info("Ticker initialised for "+ticker+" with "+dates.size()+" points");
	}
	
	public double getSpread(){ return spread; }
	
	public Ticker clone(){
		try {
			return (Ticker) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public String getName(){
		return ticker;
	}
	
	public int getDataCount(){
		return this.dates.size();
	}
	
	public Vector<Date> getDates(){
		return this.dates;
	}
	
	public Vector<Double> getCloses(){
		return this.closes;
	}
	 
	public Vector<Double> getLows(){
		return this.lows;
	}
	
	public Vector<Double> getHighs(){
		return this.highs;
	}
	
	public Vector<Double> getOpens(){
		return this.opens;
	}
	
	public Vector<OHLCDataItem> getPrices(){
		return this.prices;
	}
	
	public Vector<Double> getNormalised(Vector<Double> series){
		Vector<Double> norm=new Vector<Double>();
		Data.normaliseDoubleSet(series, series, norm, series.size());
		return norm;
	}
	
	public Vector<Double> getNormalisedDeltas(Vector<Double> series, int delta){
		Vector<Double> vDelta=new Vector<Double>();
		Data.calculateDeltas(series, vDelta, delta);
		Vector<Double> nDelta=new Vector<Double>();
		Data.normaliseDoubleSet(vDelta, vDelta, nDelta, vDelta.size());
		return nDelta;
	}
	
	public Vector<Double> getDeltas(Vector<Double> series, int delta){
		Vector<Double> vDelta=Data.calculateDeltas(series, new Vector<Double>(), delta);
		return vDelta;
	}
	
	public Vector<Double> applyDeltas(Vector<Double> series, Vector<Double> deltas, int delta){
		Vector<Double> newSeries=new Vector<Double>();
		for(int i=0;i<series.size()-delta; i++){
			newSeries.add(series.get(i+delta)+deltas.get(i));
		}
		return newSeries;
	}
	
	public Vector<Double> unNormaliseDeltas(Vector<Double> series, Vector<Double> range){
		Vector<Double> vData=new Vector<Double>();
		//System.out.println("Unnormalising "+range.size()+" points ");
		Data.unNormaliseDoubleSet(range, vData, series, range.size());
		return vData;
	}
	
	
	
	/*@SuppressWarnings("rawtypes")
	public void setupNetTraining(Vector<Vector> inputs, Vector<Vector> outputs, int start, int end){
		
		trainingSet=Data.createInputSet(inputs, outputs, start, end);
		mlp = new MultiLayerPerceptron(TransferFunctionType.SIGMOID,inputs.size(),(inputs.size()/2),outputs.size());
		File nnet=new File("/tmp/"+this.ticker+".nnet");
		if(nnet.exists()){ System.out.println("NNET exists at: "+nnet.getAbsolutePath()); return; }


	}
	
	@SuppressWarnings("rawtypes")
	public Vector<Double> testNet(Vector<Vector> inputs, Vector<Vector> outputs, int start, int end){

		TrainingSet validationSet=Data.createInputSet(inputs, outputs, start, end);
		NeuralNetwork mlp = NeuralNetwork.load("/tmp/"+this.ticker+".nnet");
		Vector<Double> errorVector=new Vector<Double>(), outputVector=new Vector<Double>();
		for(int i=start;i<end;i++){
			//System.out.println("Validating set "+(i-start));
			mlp.setInput(validationSet.elementAt(i-start).getInputArray());
			mlp.calculate();
			double[] networkOutput = mlp.getOutput();
			outputVector.add(networkOutput[0]);
			double[] idealOutput = validationSet.elementAt(i-start).getIdealArray();
			//System.out.println("Net output: "+Arrays.toString(networkOutput)+" vs "+Arrays.toString(idealOutput));
			for(int j=0;j<networkOutput.length;j++){
				while(errorVector.size()<=j){ errorVector.add(0.0); }
				errorVector.setElementAt(errorVector.get(j)+Math.abs(Math.abs(networkOutput[j])-Math.abs(idealOutput[j])), j);
			}
		}
		for(int i=0;i<errorVector.size();i++){
			errorVector.setElementAt(errorVector.get(i)/validationSet.size(), i);
			System.out.println(" Error updated to: "+errorVector.get(i));
		}
		return outputVector;
	}*/

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public String makePicture(Vector<Vector> sets, int width, int height, String id){
		JFreeChart chart = ChartFactory.createTimeSeriesChart("Chart", "", "", genXYDataset(this.prices, sets.get(0),"Series 0"), true, false, false);
		XYPlot plot = (XYPlot) chart.getPlot();
		for(int i=1;i<sets.size(); i++){
			plot.setDataset(i, genXYDataset(this.prices, sets.get(i),"Series "+i));
			plot.setRenderer(i,new StandardXYItemRenderer());
		}
		try {
			File file=new File("/opt/jboss/jboss-6.0.0.20100911-M5/server/MarketWatcherMember1/deploy/ROOT.war/images/Chart-"+ticker+"-"+id+".jpg");
			ChartUtilities.saveChartAsJPEG(file, chart, width, height);
			//System.out.println("Wrote Chart: "+file.getAbsolutePath());
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "/images/Chart-"+ticker+"-"+id+".jpg";
	}
	
	@SuppressWarnings({"rawtypes", "unchecked"})
	public void writePicture(Vector<Vector> sets, int width, int height, OutputStream out){
		JFreeChart chart = ChartFactory.createTimeSeriesChart("Chart", "", "", genXYDataset(this.prices, sets.get(0),"Series 0"), true, false, false);
		XYPlot plot = (XYPlot) chart.getPlot();
		for(int i=1;i<sets.size(); i++){
			plot.setDataset(i, genXYDataset(this.prices, sets.get(i),"Series "+i));
			plot.setRenderer(i,new StandardXYItemRenderer());
		}
		try {
			ChartUtilities.writeChartAsJPEG(out, chart, width, height);
			//System.out.println("Wrote Chart: "+file.getAbsolutePath());
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	private XYDataset genXYDataset(Vector<OHLCDataItem> dates, Vector<Double> series, String title){
    	TimeSeriesCollection tsc = new TimeSeriesCollection();
    	TimeSeries ts = new TimeSeries(title);
		for(int i=0;i<series.size();i++){
			int dateIndex=dates.size()-series.size()+i;
			ts.add(new TimeSeriesDataItem(new Day(dates.get(dateIndex).getDate()), series.get(i)));
		}
		tsc.addSeries(ts);
		return tsc;
	}

	/*public Object execute() {
		SupervisedLearning s=(SupervisedLearning)mlp.getLearningRule();
		s.setMaxError(0.00001);
		s.setMaxIterations(10000);
		mlp.learnInNewThread(trainingSet);
		while(!s.isStopped()){
			try {
				//System.out.println("Error: "+s.getPreviousEpochError()+" on iteration "+s.getCurrentIteration());
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("Trained to error value: "+s.getPreviousEpochError());
		return mlp;
	}*/


}
